//
//  CustomLabel.m
//  Etion
//
//  Created by wu jingxing on 12-7-10.
//  Copyright (c) 2012年 GuangZhouXuanWu. All rights reserved.
//

#import "StaticTextLabel.h"

@implementation NSAttributedString (CaleSize)

- (CGSize)attributedStringSize:(CGSize)containSize
{
    CTFramesetterRef ref = CTFramesetterCreateWithAttributedString((__bridge_mm CFAttributedStringRef) self);
//    CGSize size = CTFramesetterSuggestFrameSizeWithConstraints(ref, CFRangeMake(0, ((NSAttributedString *) self).length), NULL, containSize, NULL);
//    CFRelease(ref);
//    return size;

    __block CGFloat lineSpace = 0;
    [self enumerateAttribute:(__bridge_mm NSString *) kCTParagraphStyleAttributeName inRange:NSMakeRange(0, self.length) options:0 usingBlock:^(id value, NSRange range, BOOL *stop)
    {
        CTParagraphStyleRef paragraphStyle = (CTParagraphStyleRef) value;
        BOOL b = CTParagraphStyleGetValueForSpecifier(paragraphStyle, kCTParagraphStyleSpecifierLineSpacingAdjustment, sizeof(lineSpace), &lineSpace);
        if (b != YES)
            lineSpace = 0;
        *stop = YES;
    }];

    CGSize actualSize = CGSizeMake(0, 0);

    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddRect(path, NULL, CGRectMake(0, 0, containSize.width, containSize.height));

    CTFrameRef frame = CTFramesetterCreateFrame(ref, CFRangeMake(0, 0), path, NULL);
    CFRelease(path);

    NSArray *lines = (__bridge_mm NSArray *) CTFrameGetLines(frame);
    CGPoint origins[lines.count];
    CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), origins);
    for (NSUInteger i = 0; i < lines.count; i++)
    {
        CGFloat lineWidth = 0;
        CGFloat lineMaxHeight = 0;

        CTLineRef line = (__bridge_mm CTLineRef) lines[i];

//        CGFloat ascent=0,descet=0,leading=0;
//        lineWidth=CTLineGetTypographicBounds(line, &ascent, &descet, &leading);
//        lineMaxHeight=MAX(lineMaxHeight,ascent+descet/*+leading*/);

        NSArray *runs = (__bridge_mm NSArray *) CTLineGetGlyphRuns(line);
        for (NSUInteger j = 0; j < runs.count; j++)
        {
            CTRunRef run = (__bridge_mm CTRunRef) runs[j];

            CGFloat ascent = 0, descet = 0, leading = 0;
            CGFloat width = (CGFloat) CTRunGetTypographicBounds(run, CFRangeMake(0, 0), &ascent, &descet, &leading);

            lineWidth += width;
            lineMaxHeight = MAX(lineMaxHeight, ascent + descet/*+leading*/);
        }

        actualSize = CGSizeMake(MAX(actualSize.width, lineWidth), actualSize.height + lineMaxHeight);
    }

    if (lines.count > 0)
        actualSize.height += (lines.count - 1) * lineSpace;

    CFRelease(frame);

    actualSize.width=ceilf(actualSize.width);
    actualSize.height=ceilf(actualSize.height)+1;
    
    CFRelease(ref);
    
    return actualSize;
}

@end

@interface CStaticTextLabel ()
{
    ECustomLabelClickType _clicktype;

    __unsafe_unretained id <CStaticTextLabelDelegate> _delegate;

    NSAttributedString *_attributedString;

//    CATextLayer *_attributedtextlager;

    UITouchPhase _touchphase;

    NSRange _touchstringrange;

    CGFloat _lineSpace;
}

@end

@implementation CStaticTextLabel

@synthesize delegate = _delegate;

@synthesize clicktype = _clicktype;

@synthesize szTag;

- (id)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame])
    {
    self.backgroundColor = [UIColor clearColor];

    _clicktype = ECustomLabelClickTypeNormal;

    _touchphase = UITouchPhaseEnded;

    _touchstringrange.location = NSNotFound;
    }
    return self;
}

- (void)setDelegate:(id <CStaticTextLabelDelegate>)delegate
{
    _delegate = delegate;
    self.userInteractionEnabled = YES;
}

- (void)setAttributedString:(NSAttributedString *)attributedString
{
    ReleaseObj(_attributedString);
    _attributedString = [attributedString retain_mm];

    [self setNeedsDisplay];

//    if (_attributedString == nil)
//    {
//        [_attributedtextlager removeFromSuperlayer];
//        ReleaseObj(_attributedtextlager);
//    }
//    else
//    {
//        if (_attributedtextlager == nil)
//        {
//            _attributedtextlager = [CATextLayer new];
//            _attributedtextlager.frame = self.bounds;
//            _attributedtextlager.contentsScale = [UIScreen mainScreen].scale;
//            self.numberOfLines = super.numberOfLines;
//            self.textAlignment = super.textAlignment;
//            self.lineBreakMode = super.lineBreakMode;
//            [self.layer addSublayer:_attributedtextlager];
//        }
//        _attributedtextlager.string = attributedString;
//    }
}

- (CGSize)attributedStringSize
{
    return [self attributedStringSize:CGSizeMake(self.width, CGFLOAT_MAX)];
}

- (CGSize)attributedStringSize:(CGSize)containSize
{
    if (_attributedString == nil)
        return CGSizeMake(0, 0);
    return [_attributedString attributedStringSize:containSize];
}

/*
- (void)setFont:(UIFont *)font
{
    super.font = font;
    if (_attributedtextlager != nil)
    {
        _attributedtextlager.font = font.fontName;
        _attributedtextlager.fontSize = font.pointSize;
    }
}

- (void)setTextColor:(UIColor *)textColor
{
    super.textColor = textColor;
    if (_attributedtextlager != nil)
    {
        _attributedtextlager.foregroundColor = textColor.CGColor;
    }
}
*/

- (void)setTextAlignment:(NSTextAlignment)textAlignment
{
    super.textAlignment = textAlignment;
    /*
    if (_attributedtextlager != nil)
    {
        switch (textAlignment)
        {
            case NSTextAlignmentLeft:
            {
                _attributedtextlager.alignmentMode = kCAAlignmentLeft;
                break;
            }
            case NSTextAlignmentCenter:
            {
                _attributedtextlager.alignmentMode = kCAAlignmentCenter;
                break;
            }
            case NSTextAlignmentRight:
            {
                _attributedtextlager.alignmentMode = kCAAlignmentRight;
                break;
            }
            case NSTextAlignmentNatural:
            {
                _attributedtextlager.alignmentMode = kCAAlignmentNatural;
                break;
            }
            case NSTextAlignmentJustified:
            {
                _attributedtextlager.alignmentMode = kCAAlignmentJustified;
                break;
            }
        }
    }
     */
}

- (void)setLineBreakMode:(NSLineBreakMode)lineBreakMode
{
    super.lineBreakMode = lineBreakMode;
    /*
    if (_attributedtextlager != nil)
    {
        switch (lineBreakMode)
        {
            case NSLineBreakByWordWrapping:
            case NSLineBreakByCharWrapping:
            case NSLineBreakByClipping:
            {
                _attributedtextlager.truncationMode = kCATruncationNone;
                break;
            }
            case NSLineBreakByTruncatingHead:
            {
                _attributedtextlager.truncationMode = kCATruncationStart;
                break;
            }
            case NSLineBreakByTruncatingTail:
            {
                _attributedtextlager.truncationMode = kCATruncationEnd;
                break;
            }
            case NSLineBreakByTruncatingMiddle:
            {
                _attributedtextlager.truncationMode = kCATruncationMiddle;
                break;
            }
        }
    }
     */
}

- (void)setNumberOfLines:(NSInteger)numberOfLines
{
    super.numberOfLines = numberOfLines;
    /*
    if (_attributedtextlager != nil)
        _attributedtextlager.wrapped = numberOfLines > 0 ? NO : YES;
     */
}

- (void)setFrame:(CGRect)frame
{
    super.frame = frame;
    if (_attributedString != nil)
        [self setNeedsDisplay];
}

- (CGSize)sizeThatFits:(CGSize)size
{
    if (_attributedString == nil)
        return [super sizeThatFits:size];
    return [self attributedStringSize];
}

//-(CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines
//{
//    if(_attributedString==nil)
//        return [super textRectForBounds:bounds limitedToNumberOfLines:numberOfLines];
//    
//    CGSize textSize = CTFramesetterSuggestFrameSizeWithConstraints(_framesetter, CFRangeMake(0, _attributedString.length), NULL, bounds.size, NULL);
//    
//    bounds.size=textSize;
//    
//    return bounds;
//}

- (void)drawRect:(CGRect)rect
{
    if (_attributedString == nil)
        [super drawRect:rect];
    else
    {
        CGRect originRect = rect;

        rect.size.height += (rect.size.height * 2);

        CGContextRef ctx = UIGraphicsGetCurrentContext();
        CGContextTranslateCTM(ctx, 0, rect.size.height);
        CGContextScaleCTM(ctx, 1, -1);

        CGMutablePathRef path = CGPathCreateMutable();

        CGPathAddRect(path, NULL, rect);

        CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge_mm CFAttributedStringRef) _attributedString);
        
        CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL);
        CFRelease(path);

        //    CTFrameDraw(frame, ctx);

        __block CGFloat lineSpace = 0;
        [_attributedString enumerateAttribute:(__bridge_mm NSString *) kCTParagraphStyleAttributeName inRange:NSMakeRange(0, _attributedString.length) options:0 usingBlock:^(id value, NSRange range, BOOL *stop)
        {
            CTParagraphStyleRef paragraphStyle = (CTParagraphStyleRef) value;
            BOOL b = CTParagraphStyleGetValueForSpecifier(paragraphStyle, kCTParagraphStyleSpecifierLineSpacingAdjustment, sizeof(lineSpace), &lineSpace);
            if (b != YES)
                lineSpace = 0;
            *stop = YES;
        }];

        NSArray *lines = (__bridge_mm NSArray *) CTFrameGetLines(frame);
        CGPoint origins[lines.count];
        CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), origins);

        CGFloat totalLineHeight = 0;

        CGFloat lineMaxY = 0;
        if (lines.count > 0)
            lineMaxY = origins[0].y;
        for (NSUInteger i = 0; i < lines.count; i++)
        {
            CTLineRef line = (__bridge_mm CTLineRef) lines[i];

            CGFloat lineMaxHeight = 0;

            NSArray *runs = (__bridge_mm NSArray *) CTLineGetGlyphRuns(line);

            switch (_touchphase)
            {
                case UITouchPhaseBegan:
                {
                    CGRect linkRect = CGRectMake(CGFLOAT_MAX, 0, 0, 0);
                    UIColor *linkColor = nil;

                    for (NSUInteger j = 0; j < runs.count; j++)
                    {
                        CTRunRef run = (__bridge_mm CTRunRef) runs[j];

                        CFRange range = CTRunGetStringRange(run);

                        if (NSLocationInRange(range.location, _touchstringrange))
                        {
                            NSDictionary *att = (__bridge_mm NSDictionary *) CTRunGetAttributes(run);
                            linkColor = [att objectForKey:CustomAttributeStringKeyLinkSection];
                            if (linkColor != nil)
                            {
                                CGFloat ascent = 0, descet = 0, leading = 0;
                                CGFloat width = (CGFloat) CTRunGetTypographicBounds(run, CFRangeMake(0, 0), &ascent, &descet, &leading);

                                CGFloat xOffset = CTLineGetOffsetForStringIndex(line, CTRunGetStringIndicesPtr(run)[0], NULL);

                                linkRect = CGRectMake(MIN(linkRect.origin.x, origins[i].x + xOffset), lineMaxY - descet, linkRect.size.width + width, MAX(linkRect.size.height, ascent + descet));
                            }
                        }
                    }

                    if (linkColor != nil&& linkRect.origin.x != CGFLOAT_MAX)
                    {
                        CGContextSetFillColorWithColor(ctx, linkColor.CGColor);
                        UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:linkRect cornerRadius:2];
                        CGContextAddPath(ctx, path.CGPath);
                        CGContextFillPath(ctx);
                    }
                    break;
                }
                default:
                {
                    break;
                }
            }


            for (NSUInteger j = 0; j < runs.count; j++)
            {
                CTRunRef run = (__bridge_mm CTRunRef) runs[j];

                CGFloat ascent = 0, descet = 0;
                CTRunGetTypographicBounds(run, CFRangeMake(0, 0), &ascent, &descet, NULL);
                CGContextSetTextPosition(ctx, origins[i].x, lineMaxY /*+ descet*/);

                lineMaxHeight = MAX(lineMaxHeight, ascent + descet);

                //当所有行间距和字体大小一致时才能这样预测剩下的空间能否继续绘字体
                if (j == 0 && i <= lines.count - 2 && lines.count >=2)
                {
                    if (totalLineHeight + (lineMaxHeight + lineSpace) > originRect.size.height)
                    {
                        i = lines.count;
                        j = runs.count;
                        CFRange r = CTLineGetStringRange(line);
                        NSString *lastString = [_attributedString.string substringWithRange:NSMakeRange(r.location, r.length)];
                        //   lastString=[lastString substringToIndex:lastString.length-2];
                        //   lastString=[NSString stringWithFormat:@"%@……",lastString];
                        NSMutableDictionary *dicAtt = [[NSMutableDictionary new]autorelease_mm];
                        [_attributedString enumerateAttributesInRange:NSMakeRange(r.location, r.length) options:0 usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop)
                        {
                            [dicAtt addEntriesFromDictionary:attrs];
                        }];
                        NSAttributedString *lastAttStr = [[[NSAttributedString alloc] initWithString:lastString attributes:dicAtt]autorelease_mm];
                        CTLineRef lastLineRef = CTLineCreateWithAttributedString((__bridge_mm CFAttributedStringRef) lastAttStr);
                        NSAttributedString *trunAttStr = [[[NSAttributedString alloc] initWithString:@"……" attributes:dicAtt]autorelease_mm];
                        CTLineRef trunLineRef = CTLineCreateWithAttributedString((__bridge_mm CFAttributedStringRef) trunAttStr);
                        CTLineRef lastTrunlineRef = CTLineCreateTruncatedLine(lastLineRef, rect.size.width - 10, kCTLineTruncationEnd, trunLineRef);
                        CTLineDraw(lastTrunlineRef, ctx);
                        CFRelease(lastLineRef);
                        CFRelease(trunLineRef);
                        CFRelease(lastTrunlineRef);
                    }
                    else
                        CTRunDraw(run, ctx, CFRangeMake(0, 0));
                }
                else
                    CTRunDraw(run, ctx, CFRangeMake(0, 0));
            }

            lineMaxY -= (lineMaxHeight + lineSpace);

            totalLineHeight += (lineMaxHeight + lineSpace);
        }

        CFRelease(frame);
        
        CFRelease(framesetter);
    }
}

- (NSUInteger)characterIndexAtPoint:(CGPoint)point
{
    NSUInteger nIndex = NSNotFound;

//    CGRect textRect=[self textRectForBounds:self.bounds limitedToNumberOfLines:self.numberOfLines];
//    if(CGRectContainsPoint(textRect, point) ==NO)
//        return nIndex;

    //转换为绘CoreText的坐标
//    point=CGPointMake(point.x-textRect.origin.x, point.y-textRect.origin.y);
//    point=CGPointMake(point.x, textRect.size.height-point.y);

    CGRect textRect = self.bounds;
    textRect.size.height += textRect.size.height;
    point = CGPointMake(point.x, textRect.size.height - point.y);

    __block CGFloat lineSpace = 0;
    [_attributedString enumerateAttribute:(__bridge_mm NSString *) kCTParagraphStyleAttributeName inRange:NSMakeRange(0, _attributedString.length) options:0 usingBlock:^(id value, NSRange range, BOOL *stop)
    {
        CTParagraphStyleRef paragraphStyle = (CTParagraphStyleRef) value;
        BOOL b = CTParagraphStyleGetValueForSpecifier(paragraphStyle, kCTParagraphStyleSpecifierLineSpacingAdjustment, sizeof(lineSpace), &lineSpace);
        if (b != YES)
            lineSpace = 0;
        *stop = YES;
    }];

    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddRect(path, NULL, textRect);

    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge_mm CFAttributedStringRef) _attributedString);
    
    CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL);

    NSArray *lines = (__bridge_mm NSArray *) CTFrameGetLines(frame);
    CGPoint origins[lines.count];
    CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), origins);

    CGFloat lineMaxY = 0;
    if (lines.count > 0)
        lineMaxY = origins[0].y;
    for (NSInteger i = 0; i < lines.count; i++)
    {
        CGPoint origin = origins[i];
        origin.y = lineMaxY;

//        CTLineRef line=(__bridge_mm CTLineRef)lines[i];
//        CGFloat ascent=0,descent=0,leading=0;
//        CGFloat width=(CGFloat)CTLineGetTypographicBounds(line, &ascent, &descent, &leading);
//        CGFloat yMin=floorf(origin.y-descent);
//        CGFloat yMax=ceilf(origin.y+ascent);
//
//        lineMaxY-=(ascent+descent);
//        
//        if(point.y>yMax)
//            break;
//
//        if(point.y>=yMin)
//        {
//            if(point.x>=origin.x&&point.x<=origin.x+width)
//            {
//            //    CGPoint relativePoint=CGPointMake(point.x-origin.x, point.y-origin.y);
//                nIndex=CTLineGetStringIndexForPosition(line, point);
//                break;
//            }
//        }

        CGFloat lineMaxHeight = 0;

        CTLineRef line = (__bridge_mm CTLineRef) lines[i];
        NSArray *runs = (__bridge_mm NSArray *) CTLineGetGlyphRuns(line);
        for (NSUInteger j = 0; j < runs.count; j++)
        {
            CTRunRef run = (__bridge_mm CTRunRef) runs[j];

            CGFloat ascent = 0, descent = 0, leading = 0;
            CGFloat width = (CGFloat)CTRunGetTypographicBounds(run, CFRangeMake(0, 0), &ascent, &descent, &leading);
            CGFloat yMin = origin.y - descent;
            CGFloat yMax = origin.y + ascent;

            CGPoint runPoint = CTRunGetPositionsPtr(run)[0];

            lineMaxHeight = MAX(lineMaxHeight, ascent + descent);

            if (point.y >= yMin && point.y <= yMax)
            {
                if (point.x >= runPoint.x && point.x <= runPoint.x + width)
                {
                    nIndex = CTRunGetStringIndicesPtr(run)[0];
                    i = lines.count;
                    j = runs.count;
                }
            }
        }

        lineMaxY -= (lineMaxHeight + lineSpace);
    }

    CFReleaseRef(path);
    CFReleaseRef(frame);
    CFReleaseRef(framesetter);

    return nIndex;
}

- (NSRange)linkAtCharacterIndex:(NSUInteger)nIndex
{
    __block NSRange r;
    r.location = NSNotFound;
    [_attributedString enumerateAttribute:CustomAttributeStringKeyLinkSection inRange:NSMakeRange(0, _attributedString.length) options:0 usingBlock:^(id value, NSRange range, BOOL *stop)
    {
        if (value != nil&& NSLocationInRange(nIndex, range) == YES)
        {
            r = range;
            *stop = YES;
        }
    }];
    return r;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    _touchstringrange.location = NSNotFound;

    if (_attributedString == nil)
        return;

    UITouch *touch = [touches anyObject];
    CGPoint p = [touch locationInView:self];
    if (CGRectContainsPoint(self.bounds, p) != YES)
        return;

    NSRange range = [self linkAtCharacterIndex:[self characterIndexAtPoint:p]];
    if (range.location != NSNotFound)
    {
        _touchphase = ((UITouch *) [touches anyObject]).phase;
        [self setNeedsDisplay];
    }

    _touchstringrange = range;
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint p = [touch locationInView:self];
    if (CGRectContainsPoint(self.bounds, p) != YES)
        return;

    NSRange range = _touchstringrange;

    _touchstringrange.location = NSNotFound;

    if (_attributedString != nil)
        [self setNeedsDisplay];

    if (range.location != NSNotFound)
    {
        if ([_delegate respondsToSelector:@selector(staticTextLabelLinkSectionClick:sectionRange:text:)])
            [_delegate staticTextLabelLinkSectionClick:self sectionRange:range text:[_attributedString.string substringWithRange:range]];
    }
    else
    {
        switch ((NSInteger) _clicktype)
        {
            case ECustomLabelClickTypeNormal:
            {
                if ([_delegate respondsToSelector:@selector(staticTextLabelClick:)])
                    [_delegate staticTextLabelClick:self];
                break;
            }
            case ECustomLabelClickTypeZoomInOut:
            {
                self.userInteractionEnabled = NO;

                CGRect f = self.bounds;
                f.size.width = [self.text stringSizeWithFont:self.font].width;
                UILabel *l = [[[UILabel alloc] initWithFrame:f] autorelease_mm];
                l.backgroundColor = [UIColor clearColor];
                l.text = self.text;
                l.font = self.font;
                l.textColor = self.textColor;
                [self addSubview:l];
                [UIView animateWithDuration:0.2 animations:^
                {
                    l.transform = CGAffineTransformMakeScale(1.1, 1.1);
                }                completion:^(BOOL finished)
                {
                    [UIView animateWithDuration:0.2 animations:^
                    {
                        l.textColor = [UIColor redColor];
                        l.transform = CGAffineTransformMakeScale(0.9, 0.9);
                    }                completion:^(BOOL finished)
                    {
                        [UIView animateWithDuration:0.2 animations:^
                        {
                            l.transform = CGAffineTransformMakeScale(1.0, 1.0);
                            self.textColor = [UIColor colorWithRed:0.2 green:0.2 blue:0.2 alpha:1];
                            l.textColor = self.textColor;
                        }                completion:^(BOOL finished)
                        {
                            self.userInteractionEnabled = YES;

                            [l removeFromSuperview];
                            if ([_delegate respondsToSelector:@selector(staticTextLabelClick:)])
                                [_delegate staticTextLabelClick:self];
                        }];
                    }];
                }];
                break;
            }
        }
    }
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    _touchstringrange.location = NSNotFound;

    if (_attributedString != nil)
        [self setNeedsDisplay];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    _touchstringrange.location = NSNotFound;

    if (_attributedString != nil)
        [self setNeedsDisplay];
}

- (void)dealloc
{
    self.szTag = nil;
    [_attributedString release_mm];
    superdealloc_mm;
}

@end
